const getConfig = require('../../utils/configUtil').getConfig;
const Logger = require('../../utils/logger').Logger('wx-pay');
const { JJUserOrder, JJUserCourse, Ctcdb, JJCourseCamp, JJUserAccountBill, JJCourse, JJCourseAccountBill, JJCourseAccount } = require('../../models/ctcdb');
const orderService = require('../order');
const BaseResp = require('../../utils/baseResp');
const errorCode = require('../../utils/errorCode');
const WxPay = require('../../utils/wxPay');
const wx = new WxPay().wx;

class Pay {

  async notify(map) {
    const sign = wx.sign(map);
    if (map.sign !== sign) {
      Logger.error(`notify sign error,my sign: ${sign}, wx sign: ${map.sign}`);
      throw new Error('sign error');
    }
    if (map.return_code === 'SUCCESS' && map.result_code === 'SUCCESS') {
      const { out_trade_no, openid, transaction_id, time_end } = map;
      let transaction;
      try {
        const order = await JJUserOrder.findOne({
          where: {
            tradeNo: out_trade_no,
            status: 0
          },
          attributes: ['tradeNo', 'id', 'orderNo', 'openId', 'jUserId', 'lUserId', 'courseId', 'price'],
          raw: true
        });
        if (!order) {
          Logger.error('订单不存在，请检查原因');
          return Promise.resolve() ;
        }
        // 修改订单的基础信息
        const update = {
          orderNo: transaction_id, // 订单号
          openId: openid, // 用户Id
          snapshot: JSON.stringify(map), // 快照存储
          // endTime: , // 结束时间
          status: 1 // 订单状态改为已支付
        };
        const { id: orderId, jUserId, lUserId, courseId, price } = order;
        const courseInfo = await JJCourse.findOne({
          where: {
            id: courseId
          },
          attributes: ['id', 'type', 'isSend', 'courseName'],
          raw: true
        });

        let userCourseStatus = 1;
        let camps = [];
        let courseName = '';
        // 强行加个判断 fixme 这里考虑下 是不是所有的课程都改成已预约
        if (courseInfo) {
          if (courseInfo.type === 1 || (courseInfo.type === 2 && courseInfo.isSend === 0)) {
            userCourseStatus = 5;
          } else {
            camps = await JJCourseCamp.findAll({
              where: {
                courseId
              },
              attributes: ['id'],
              raw: true
            });
          }
          courseName = courseInfo.courseName;
        }
       const courseAccount =  await JJCourseAccount.findOne({
          where: {
            courseId
          },
          raw: true
        });
        transaction = await Ctcdb.transaction(); // 获取事务
        await JJUserOrder.update(update, {
          where: {
            id: orderId
          },
          transaction
        });
        // 创建用户的课程
        await JJUserCourse.create({
          jUserId,
          lUserId,
          courseId,
          status: userCourseStatus,
          type: 1,
          orderId
        }, {
          transaction
        });
        // 第一次创建
        if (!courseAccount) {
          await JJCourseAccount.create({
            status: 1,
            courseId,
            lUserId,
            balance: price
          }, { transaction });
        } else {
          // 统一账户增加余额
          const sql = `update jj_course_account set balance = balance + ${ price } where jj_course_id = ${courseId}`;
          await Ctcdb.query(sql, { transaction });
        }
        await JJCourseAccountBill.create({
          amount: price,
          type: 1,
          remark: `用户购买`,
          jUserId,
          courseId
        }, {
          transaction
        });
        await JJUserAccountBill.create({
          amount: price,
          type: 'ADD_MONEY',
          remark: `充值`,
          userId: jUserId
        }, {
          transaction
        });
        await JJUserAccountBill.create({
          amount: -price,
          type: 'COURSE_BUY',
          remark: `购买${courseName}`,
          userId: jUserId
        }, {
          transaction
        });
        if (camps.length > 0) {
          const detailArr = [];
          camps.forEach((item) => {
            detailArr.push({
              jUserId,
              status: 1,
              courseId,
              campId: item.id,
              type: 2,
              lUserId
            })
          });
          await JJUserCourse.bulkCreate(detailArr, { transaction })
        }
        await JJCourse.update({
          isBuy: 1
        }, {
          where: {
            id: courseId
          },
          transaction
        });
        await transaction.commit() // 提交事务
      } catch (e) {
        if (transaction) {
          await transaction.rollback();
        }
        Logger.error(e);
      }
    } else {
      Logger.error('订单失败');
    }
  }

  async buy({ orderId, userId, openid, ip }) {
    const order = await orderService.queryOrderDetail({ orderId });
    if (order.status !== 0) {
      throw BaseResp.error(errorCode.ORDER.HAS_BUY);
    }
    const { body, price, orderNo, tradeNo } = order;
    const totalFee = Number(price) * 100;
    return new Promise((resolve, reject) => {
      return wx.createUnifiedOrder({
        openid,
        body,
        out_trade_no: tradeNo,
        total_fee: totalFee,
        spbill_create_ip: ip,
        trade_type: 'JSAPI',
        notify_url: getConfig.wechat.notifyUrl // todo 配置一下
      }, (err, result) => {
        if (err) {
          return reject(err)
        }
        if (result.return_code === 'SUCCESS') {
          if (result.result_code === 'SUCCESS') {
            const timeStamp = Math.floor(Date.now() / 1000);
            let sign = wx.sign({
              appId: result.appid,
              timeStamp,
              nonceStr: result.nonce_str,
              package: `prepay_id=${result.prepay_id}`,
              signType: 'MD5'
            });
            return resolve({
              prepayId: `prepay_id=${result.prepay_id}`,
              sign,
              nonceStr: result.nonce_str,
              appid: result.appid,
              mchid: result.mch_id,
              timestamp: timeStamp + ''
            });
          } else {
            return reject(new Error({
              err_code: 'PARAM_ERROR',
              err_code_des: '参数错误'
            }));
          }
        }
        return reject(new Error(result.return_msg));
      });
    });
  }
}

module.exports = Pay;
